using System.Collections.Generic;
using UnityEngine;

public class KineticElementMove : KineticPlanElement
{
	public MoveAnimationInfo animInfo;

	public Vector3 desiredEndPosition;

	public Vector3 desiredEndRotation;

	public bool useDesiredEnd;

	public bool canMove = true;

	public Vector3 adjustPosition;

	public float adjustAngle;

	protected Vector3 position;

	protected Quaternion rotation;

	protected Vector3 positionChange;

	protected Quaternion rotationChange;

	protected Quaternion errorRotationChange;

	public bool useSmoothStep;

	public bool startFromCurrentPosition;

	public float crossFadeDuration;

	public float lastCheckpointTime;

	public Vector3 errorPositionChange { get; protected set; }

	public override float length
	{
		get
		{
			return animInfo.clipLength;
		}
	}

	public override float durationTillEnd
	{
		get
		{
			return (length - base.ellapsedTime) / animatorSpeed;
		}
	}

	public override KineticPlan.TransformState GetEndState(KineticPlan.TransformState startState)
	{
		KineticPlan.TransformState result = startState;
		if (isActive)
		{
			result.position = startPosition;
			result.rotation = startRotation;
		}
		result.duration = durationTillEnd;
		result.rotation *= animInfo.rotationChange;
		if (useDesiredEnd)
		{
			result.position = desiredEndPosition;
		}
		else
		{
			result.position += result.rotation * animInfo.positionChange + adjustPosition;
		}
		return result;
	}

	public override void OnStart(Transform character)
	{
		base.OnStart(character);
		positionChange = Vector3.zero;
		rotationChange = Quaternion.identity;
		if (startFromCurrentPosition)
		{
			startPosition = character.position;
			startRotation = character.rotation;
		}
		position = startPosition;
		rotation = startRotation;
		errorPositionChange = Vector3.zero;
		errorRotationChange = Quaternion.identity;
		UpdateCharacterTransform();
		base.animator.speed = animatorSpeed;
		if (crossFadeDuration == 0f)
		{
			base.animator.Play(animInfo.animatorStateName, 0, 0f);
		}
		else
		{
			base.animator.CrossFade(animInfo.animatorStateName, crossFadeDuration, 0, 0f);
		}
		if (useDesiredEnd)
		{
			adjustPosition = desiredEndPosition - (startPosition + startRotation * animInfo.positionChange);
		}
	}

	public override void OnAnimatorMove()
	{
		if (base.animator == null)
		{
			return;
		}
		AnimatorStateInfo currentAnimatorStateInfo = base.animator.GetCurrentAnimatorStateInfo(0);
		if (currentAnimatorStateInfo.shortNameHash == Animator.StringToHash(animInfo.animatorStateName) && isActive)
		{
			float num = base.ellapsedTime;
			base.ellapsedTime += GGGameTime.deltaTime * animatorSpeed;
			base.ellapsedRealTime += GGGameTime.deltaTime;
			KineticAnimationInfo.CheckpointInfo nextCheckpointInfo = GetNextCheckpointInfo(num);
			if (nextCheckpointInfo != null && nextCheckpointInfo.time < base.ellapsedTime)
			{
				CalculateCheckpointErorr(nextCheckpointInfo, num, base.ellapsedTime);
			}
			float value = base.ellapsedTime / animInfo.clipLength;
			float t = animInfo.adjustmentsTimeWindow.InverseLerp(value);
			if (useSmoothStep)
			{
				t = Mathf.SmoothStep(0f, 1f, t);
			}
			Quaternion quaternion = Quaternion.Lerp(Quaternion.identity, Quaternion.AngleAxis(adjustAngle, Vector3.up), t);
			positionChange += Quaternion.Inverse(quaternion) * base.animator.deltaPosition;
			rotationChange = base.animator.deltaRotation * rotationChange;
			Vector3 vector = position;
			position = startPosition + positionChange + AdjustPosition();
			rotation = quaternion * rotationChange * startRotation;
			UpdateCharacterTransform();
			if ((currentAnimatorStateInfo.normalizedTime >= 1f && !base.animator.IsInTransition(0)) || base.ellapsedTime + crossFadeDuration * animatorSpeed >= animInfo.clipLength)
			{
				EndAnimation();
			}
		}
	}

	protected virtual Vector3 AdjustPosition()
	{
		float value = base.ellapsedTime / animInfo.clipLength;
		float t = animInfo.adjustmentsTimeWindow.InverseLerp(value);
		return Vector3.Lerp(Vector3.zero, adjustPosition, t) + Vector3.Lerp(Vector3.zero, errorPositionChange, (base.ellapsedTime - lastCheckpointTime) / (animInfo.clipLength - lastCheckpointTime));
	}

	protected virtual void CalculateCheckpointErorr(KineticAnimationInfo.CheckpointInfo checkpoint, float prevTime, float time)
	{
		Vector3 vector = positionChange + Vector3.Lerp(Vector3.zero, base.animator.deltaPosition, (checkpoint.time - prevTime) / (time - prevTime));
		errorPositionChange = startRotation * (checkpoint.positionChange - Quaternion.Inverse(startRotation) * vector);
		errorRotationChange = Quaternion.Inverse(rotationChange) * checkpoint.rotationChange;
		lastCheckpointTime = time;
	}

	protected KineticAnimationInfo.CheckpointInfo GetNextCheckpointInfo(float time)
	{
		List<KineticAnimationInfo.CheckpointInfo> checkpoints = animInfo.checkpoints;
		if (checkpoints == null)
		{
			return null;
		}
		foreach (KineticAnimationInfo.CheckpointInfo item in checkpoints)
		{
			if (item.time >= time)
			{
				return item;
			}
		}
		return null;
	}

	public override void OnLateUpdate()
	{
	}

	public virtual void EndAnimation()
	{
		isActive = false;
		UpdateCharacterTransform();
	}

	protected void UpdateCharacterTransform()
	{
		if (canMove)
		{
			character.position = position;
			character.rotation = rotation;
		}
	}
}
